﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;

using Domain.Uow;

namespace Infrastructure.Data.Uow
{
    public class EfRepository<T> :
        Domain.Uow.IRepository<T> where T : Domain.Entity.EntityBase
    {
        #region Members

        readonly UnitOfWorkIQueryable uow;

        readonly IDbSet<T> entities;

        public IUnitOfWork Uow { get { return uow; } }

        #endregion

        #region Constructor

        /// <summary>
        /// Create a new instance of repository
        /// </summary>
        /// <param name="unitOfWork">Associated Unit Of Work</param>
        public EfRepository(UnitOfWorkIQueryable unitOfWork)
        {
            if (unitOfWork == (IUnitOfWork)null)
            {
                throw new ArgumentNullException("unitOfWork");
            }
            else
            {
                uow = unitOfWork;
                entities = uow.SetEntity<T>();
            }
        }

        #endregion

        #region repository

        public virtual void Add(T item)
        {
            if (item != (T)null)
            {
                this.entities.Add(item);
            }
            else
            {
                Infrastructure.Data.Uow.Log.LoggerRepositoryManager.AddLogInfo(1, 0, string.Empty, string.Empty,
                    "add object is null " + typeof(T).ToString(), string.Empty, string.Empty);
            }
        }


        public virtual void Modify(T item)
        {
            if (item != (T)null)
            {
                this.uow.Commit();
            }
            else
            {
                Infrastructure.Data.Uow.Log.LoggerRepositoryManager.AddLogInfo(1, 0, string.Empty, string.Empty,
                    "modify object " + typeof(T).ToString(), string.Empty, string.Empty);
            }
        }

        public virtual void Delete(T item)
        {
            if (item != (T)null)
            {
                this.entities.Remove(item);
            }
            else
            {
                Infrastructure.Data.Uow.Log.LoggerRepositoryManager.AddLogInfo(1, 0, string.Empty, string.Empty,
                    "delete object is null " + typeof(T).ToString(), string.Empty, string.Empty);
            }
        }

        public virtual T Get(int id)
        {
            if (id > 0)
            {
                return this.entities.Find(id);
            }
            else
            {
                return null;
            }
        }

        public virtual IQueryable<T> GetList()
        {
            return this.entities;
        }

        public virtual IQueryable<T> GetList(Domain.Uow.Specification.ISpecification<T> specification)
        {
            return this.entities.Where(specification.SatisfiedBy()).AsQueryable();
        }

        public virtual IQueryable<T> GetList<KProperty>(int pi, int take, System.Linq.Expressions.Expression<Func<T, KProperty>> orderby, bool ascending)
        {
            var set = this.entities;
            pi = (pi - 1) < 0 ? 0 : (pi - 1);
            if (ascending)
            {
                return set.OrderBy(orderby).Skip(pi * take).Take(take).AsQueryable();
            }
            else
            {
                return set.OrderByDescending(orderby).Skip(pi * take).Take(take).AsQueryable();
            }
        }

        public virtual IQueryable<T> GetList(System.Linq.Expressions.Expression<Func<T, bool>> filter)
        {
            return this.entities.Where(filter);
        }

        #endregion
    }
}